﻿using GeoParser;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;

namespace GeoLibraryTest
{
    /// <summary>
    ///This is a test class for GeoPoint and is intended
    ///to contain all GeoPoint Unit Tests
    ///</summary>
	[TestClass()]
	public class GeoPointTest
	{
		private TestContext testContextInstance;

		/// <summary>
		///Gets or sets the test context which provides
		///information about and functionality for the current test run.
		///</summary>
		public TestContext TestContext
		{
			get
			{
				return testContextInstance;
			}
			set
			{
				testContextInstance = value;
			}
		}

		#region Additional test attributes
		// 
		//You can use the following additional attributes as you write your tests:
		//
		//Use ClassInitialize to run code before running the first test in the class
		//[ClassInitialize()]
		//public static void MyClassInitialize(TestContext testContext)
		//{
		//}
		//
		//Use ClassCleanup to run code after all tests in a class have run
		//[ClassCleanup()]
		//public static void MyClassCleanup()
		//{
		//}
		//
		//Use TestInitialize to run code before running each test
		//[TestInitialize()]
		//public void MyTestInitialize()
		//{
		//}
		//
		//Use TestCleanup to run code after each test has run
		//[TestCleanup()]
		//public void MyTestCleanup()
		//{
		//}
		//
		#endregion


		/// <summary>
		///A test for Longitude
		///</summary>
		[TestMethod]
		public void LongitudeTest()
		{
			// Arrange
			string latlong = "0 0";
			GeoPoint target = new GeoPoint(latlong);
			double expected = 1.0;
	
			// Act
			target.Longitude = expected;
			double actual = target.Longitude;

			// Assert	
			Assert.AreEqual(expected, actual);
		}

		/// <summary>
		///A test for Latitude
		///</summary>
		[TestMethod]
		public void LatitudeTest()
		{
			// Arrange
			string latlong = "0 0";
			GeoPoint target = new GeoPoint(latlong);
			double expected = 1.0;

			// Act
			target.Latitude = expected;
			double actual = target.Latitude;

			// Assert	
			Assert.AreEqual(expected, actual);
		}

		/// <summary>
		///A test for ToString
		///</summary>
		[TestMethod]
		public void ToStringTest()
		{
			// Arrange
			GeoPoint target = new GeoPoint(50, -10);
			string expected = "50 -10";

			// Act
			string actual = target.ToString();

			// Assert	
			Assert.AreEqual(expected, actual);
		}

		/// <summary>
		///A test for RadiansToDegrees: 0 -> 0
		///</summary>
		[TestMethod]
		public void RadiansToDegreesTest_0()
		{
			// Arrange
			double radians = 0F;
			double expected = 0F;

			// Act
			double actual = GeoPoint.RadiansToDegrees(radians);

			// Assert	
			Assert.AreEqual(expected, actual);
		}

		/// <summary>
		///A test for RadiansToDegrees: PI -> 180
		///</summary>
		[TestMethod]
		public void RadiansToDegreesTest_180()
		{
			// Arrange
			double radians = Math.PI;
			double expected = 180F;

			// Act
			double actual = GeoPoint.RadiansToDegrees(radians);

			// Assert	
			Assert.AreEqual(expected, actual);
		}

		/// <summary>
		///A test for ParseDegrees
		///</summary>
		[TestMethod]
		public void ParseDegreesTest_Int()
		{
			// Arrange
			string degrees = "15";
			double expected = 15F;
			
			// Act
			double actual = GeoPoint.ParseDegrees(degrees);
			
			// Assert
			Assert.AreEqual(expected, actual);
		}

		/// <summary>
		///A test for ParseDegrees
		///</summary>
		[TestMethod]
		public void ParseDegreesTest_IntDeg()
		{
			// Arrange
			string degrees = "15*";
			double expected = 15F;

			// Act
			double actual = GeoPoint.ParseDegrees(degrees);

			// Assert
			Assert.AreEqual(expected, actual);
		}

		/// <summary>
		///A test for ParseDegrees
		///</summary>
		[TestMethod]
		public void ParseDegreesTest_IntDegInt()
		{
			// Arrange
			string degrees = "15*30";
			double expected = 15.5;

			// Act
			double actual = GeoPoint.ParseDegrees(degrees);

			// Assert
			Assert.AreEqual(expected, actual);
		}

		/// <summary>
		///A test for ParseDegrees
		///</summary>
		[TestMethod]
		public void ParseDegreesTest_IntDegIntMinInt()
		{
			// Arrange
			string degrees = "15*00'45";
			double expected = 15.0125;

			// Act
			double actual = GeoPoint.ParseDegrees(degrees);

			// Assert
			Assert.AreEqual(expected, actual);
		}

		/// <summary>
		///A test for ParseDegrees
		///</summary>
		[TestMethod]
		public void ParseDegreesTest_IntDegIntMinIntCompass()
		{
			// Arrange
			string degrees = "15*00'45S";
			double expected = -15.0125;

			// Act
			double actual = GeoPoint.ParseDegrees(degrees);

			// Assert
			Assert.AreEqual(expected, actual);
		}

		/// <summary>
		///A test for Equals
		///</summary>
		[TestMethod]
		public void EqualsTest_Static_False()
		{
			// Arrange
			GeoPoint a = new GeoPoint("30 40");
			GeoPoint b = new GeoPoint("30 45");
			bool expected = false;
			
			// Act
			bool actual = GeoPoint.Equals(a, b);

			// Assert
			Assert.AreEqual(expected, actual);
		}

		/// <summary>
		///A test for Equals
		///</summary>
		[TestMethod]
		public void EqualsTest_False()
		{
			// Arrange
			string latlong = "10 -20";
			var target = new GeoPoint(latlong);
			object obj = null;
			bool expected = false;

			// Act
			bool actual = target.Equals(obj);
			
			// Assert
			Assert.AreEqual(expected, actual);
		}

		/// <summary>
		///A test for Equals
		///</summary>
		[TestMethod]
		public void EqualsTest_True()
		{
			// Arrange
			string latlong = "10 -20";
			var target = new GeoPoint(latlong);
			var other = new GeoPoint(latlong);
			bool expected = true;

			// Act
			bool actual = target.Equals(other);

			// Assert
			Assert.AreEqual(expected, actual);
		}

		/// <summary>
		///A test for DistanceBetween
		///</summary>
		[TestMethod]
		public void DistanceBetweenTest_0()
		{
			// Arrange
			GeoPoint a = new GeoPoint("30 40");
			GeoPoint b = new GeoPoint("30 40");
			Distance expected = new Distance();

			// Act
			Distance actual = GeoPoint.DistanceBetween(a, b);

			// Assert
			Assert.AreEqual(expected, actual);
		}

		/// <summary>
		///A test for DegreesToRadians 0 -> 0
		///</summary>
		[TestMethod]
		public void DegreesToRadiansTest_0()
		{
			// Arrange
			double degrees = 0F;
			double expected = 0F;
			
			// Act
			double actual = GeoPoint.DegreesToRadians(degrees);

			// Assert
			Assert.AreEqual(expected, actual);
		}

		/// <summary>
		///A test for DegreesToRadians 180 -> PI
		///</summary>
		[TestMethod]
		public void DegreesToRadiansTest_180()
		{
			// Arrange
			double degrees = 180F;
			double expected = Math.PI;

			// Act
			double actual = GeoPoint.DegreesToRadians(degrees);

			// Assert
			Assert.AreEqual(expected, actual);
		}

		/// <summary>
		///A test for Clone
		///</summary>
		[TestMethod]
		public void CloneTest()
		{
			// Arrange
			string latlong = "10 20";
			GeoPoint orig = new GeoPoint(latlong);
			GeoPoint expected = new GeoPoint(latlong);

			// Act
			GeoPoint actual = GeoPoint.Clone(orig);

			// Assert
			Assert.AreEqual(expected, actual);
			Assert.AreNotSame(expected, actual);
		}

		/// <summary>
		///A test for Average
		///</summary>
		[TestMethod]
		public void AverageTest()
		{
			// Arrange
			GeoPoint a = new GeoPoint("10 -20");
			GeoPoint b = new GeoPoint("0 -40");
			GeoPoint expected = new GeoPoint("5 -30");

			// Act
			GeoPoint actual = GeoPoint.Average(a, b);

			// Assert
			Assert.AreEqual(expected, actual);
		}

		/// <summary>
		///A test for GeoPoint Constructor
		///</summary>
		[TestMethod]
		public void GeoPointConstructorTest_String()
		{
			// Arrange
			string latlong = "10 -20";

			// Act
			GeoPoint target = new GeoPoint(latlong);

			// Assert
			Assert.AreEqual(10F, target.Latitude);
			Assert.AreEqual(-20F, target.Longitude);
		}

		/// <summary>
		///A test for GeoPoint Constructor
		///</summary>
		[TestMethod]
		public void GeoPointConstructorTest_StringString()
		{
			// Arrange
			string latitude = "5";
			string longitude = "45";

			// Act
			GeoPoint target = new GeoPoint(latitude, longitude);

			// Assert
			Assert.AreEqual(5F, target.Latitude);
			Assert.AreEqual(45F, target.Longitude);
		}

		[TestMethod]
		public void GeoPointConstructorTest_DoubleDouble()
		{
			// Arrange
			double latitude = 8F;
			double longitude = -24F;

			// Act
			GeoPoint target = new GeoPoint(latitude, longitude);

			// Assert
			Assert.AreEqual(8F, target.Latitude);
			Assert.AreEqual(-24F, target.Longitude);
		}

		[TestMethod]
		public void DegreesToStringTest_Degrees()
		{
			// Arrange
			double degrees = -25.5F;
			GeoPoint.DegreeFormat format = GeoPoint.DegreeFormat.Degrees;
			string expected = "-25.5";
			
			// Act
			string actual = GeoPoint.DegreesToString(degrees, format);
			
			// Assert
			Assert.AreEqual(expected, actual);
		}

		[TestMethod]
		public void DegreesToStringTest_Minutes()
		{
			// Arrange
			double degrees = -25.5F;
			GeoPoint.DegreeFormat format = GeoPoint.DegreeFormat.Minutes;
			string expected = "-25*30";

			// Act
			string actual = GeoPoint.DegreesToString(degrees, format);

			// Assert
			Assert.AreEqual(expected, actual);
		}

		[TestMethod]
		public void DegreesToStringTest_Seconds()
		{
			// Arrange
			double degrees = -25.5F;
			GeoPoint.DegreeFormat format = GeoPoint.DegreeFormat.Seconds;
			string expected = "-25*30'0";

			// Act
			string actual = GeoPoint.DegreesToString(degrees, format);

			// Assert
			Assert.AreEqual(expected, actual);
		}

		[TestMethod]
		public void DegreesToStringTest_DegreesSouth()
		{
			// Arrange
			double degrees = -25.5F;
			GeoPoint.DegreeFormat format = GeoPoint.DegreeFormat.Degrees | GeoPoint.DegreeFormat.NorthCompass;
			string expected = "S25.5";

			// Act
			string actual = GeoPoint.DegreesToString(degrees, format);

			// Assert
			Assert.AreEqual(expected, actual);
		}

		[TestMethod]
		public void DegreesToStringTest_MinutesSouth()
		{
			// Arrange
			double degrees = -25.5F;
			GeoPoint.DegreeFormat format = GeoPoint.DegreeFormat.Minutes | GeoPoint.DegreeFormat.NorthCompass;
			string expected = "S25*30";

			// Act
			string actual = GeoPoint.DegreesToString(degrees, format);

			// Assert
			Assert.AreEqual(expected, actual);
		}

		[TestMethod]
		public void DegreesToStringTest_SecondsSouth()
		{
			// Arrange
			double degrees = -25.5F;
			GeoPoint.DegreeFormat format = GeoPoint.DegreeFormat.Seconds | GeoPoint.DegreeFormat.NorthCompass;
			string expected = "S25*30'0";

			// Act
			string actual = GeoPoint.DegreesToString(degrees, format);

			// Assert
			Assert.AreEqual(expected, actual);
		}

		[TestMethod]
		public void DegreeSymbolTest()
		{
			// Arrange
			var oldSymbol = GeoPoint.DegreeSymbol;
			try
			{
				GeoPoint.DegreeSymbol = '|';
				double degrees = -25.5F;
				GeoPoint.DegreeFormat format = GeoPoint.DegreeFormat.Seconds | GeoPoint.DegreeFormat.NorthCompass;
				string expected = "S25|30'0";

				// Act
				string actual = GeoPoint.DegreesToString(degrees, format);

				// Assert
				Assert.AreEqual(expected, actual);
			}
			finally
			{
				GeoPoint.DegreeSymbol = oldSymbol;
			}
		}
	}
}